import { $set } from '@feng3d/serialization';
import { CubeTextureLoader3D, Mesh3D, MeshBasicMaterial3D, Node3D, PerspectiveCamera3D, Scene3D, SphereGeometry3D, WebGLRenderer3D } from 'feng3d-three';
import { StereoEffect3D } from '../../extension/effects/StereoEffect3D';

const rootPath = '../../';

let container: HTMLDivElement;
let camera: PerspectiveCamera3D;
let scene: Scene3D;
let renderer: WebGLRenderer3D;
let effect: StereoEffect3D;

const spheres: Mesh3D[] = [];

let mouseX = 0;
let mouseY = 0;

let windowHalfX = window.innerWidth / 2;
let windowHalfY = window.innerHeight / 2;

document.addEventListener('mousemove', onDocumentMouseMove);

init();
animate();

function init()
{
    container = document.createElement('div');
    document.body.appendChild(container);

    camera = new Node3D().addComponent('PerspectiveCamera3D', { fov: 60, aspect: window.innerWidth / window.innerHeight, near: 1, far: 100000 });
    camera.entity.position.z = 3200;

    scene = new Node3D().addComponent('Scene3D');
    scene.background = new CubeTextureLoader3D()
        .setPath(`${rootPath}textures/cube/Park3Med/`)
        .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);

    const geometry = $set(new SphereGeometry3D(), { radius: 100, widthSegments: 32, heightSegments: 16 });

    const textureCube = new CubeTextureLoader3D()
        .setPath(`${rootPath}textures/cube/Park3Med/`)
        .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
    textureCube.mapping = 'CubeRefractionMapping';

    const material = new MeshBasicMaterial3D({ color: 0xffffff, envMap: textureCube._texture, refractionRatio: 0.95 });

    for (let i = 0; i < 500; i++)
    {
        const mesh = new Node3D().addComponent('Mesh3D', { geometry, material });
        mesh.entity.position.x = Math.random() * 10000 - 5000;
        mesh.entity.position.y = Math.random() * 10000 - 5000;
        mesh.entity.position.z = Math.random() * 10000 - 5000;
        mesh.entity.scale.x = mesh.entity.scale.y = mesh.entity.scale.z = Math.random() * 3 + 1;
        scene.entity.addChild(mesh.entity);

        spheres.push(mesh);
    }

    //

    renderer = scene.addComponent('WebGLRenderer3D');
    renderer.setPixelRatio(window.devicePixelRatio);
    container.appendChild(renderer.domElement);

    effect = new StereoEffect3D(renderer);
    effect.setSize(window.innerWidth, window.innerHeight);

    //

    window.addEventListener('resize', onWindowResize);
}

function onWindowResize()
{
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    effect.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseMove(event)
{
    mouseX = (event.clientX - windowHalfX) * 10;
    mouseY = (event.clientY - windowHalfY) * 10;
}

//

function animate()
{
    requestAnimationFrame(animate);

    render();
}

function render()
{
    const timer = 0.0001 * Date.now();

    camera.entity.position.x += (mouseX - camera.entity.position.x) * 0.05;
    camera.entity.position.y += (-mouseY - camera.entity.position.y) * 0.05;
    camera.entity.lookAt(scene.entity.position);

    for (let i = 0, il = spheres.length; i < il; i++)
    {
        const sphere = spheres[i];

        sphere.entity.position.x = 5000 * Math.cos(timer + i);
        sphere.entity.position.y = 5000 * Math.sin(timer + i * 1.1);
    }

    effect.render(scene, camera);
}
